// ==UserScript==
// @name         查询收录
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @updateURL    https://gitee.com/great-pacey/tampermonkey/raw/master/check.inclusion.user.js
// @match        https://www.walmart.com/*
// @icon         https://www.google.com/s2/favicons?domain=walmart.com
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://unpkg.com/vue@3
// @grant        GM_registerMenuCommand
// @grant        GM_setClipboard
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// ==/UserScript==
/* global $ */

(function () {
    GM_registerMenuCommand('开始', main);
    let continueFlag = true;
    let resultForCopy = {};
    let wordsWithoutAd = [];
    let info = {};

    function insetDIV() {
        const html = `
        <div id='my-container'>
            <div id='header'>
                <p></p>
            </div>
            <br>
            <div id="body">
                <input placeholder="input id" id='productId' />
                <br><br>
                <textarea id='text'></textarea>
                <br>
                <button id='btn'>run</button>
            </div>
        </div>`;
        const container = $(html);
        $("body").append(container);
        container.css({
            position: "fixed",
            zIndex: 100,
            width: '100%',
            height: '100%',
            bottom: '-100%',
            left: 0,
            background: 'white',
            borderTop: "2px solid black"
        });
        $("#my-container #body").css({ padding: '0 20px',float:'left' })
        $("#my-container #productId").css({ width: '400px', height: '35px' })
        $("#my-container #header").css({
            paddingRight: '30px', fontSize: '20px', background: 'orange', cursor: 'pointer',
            height: '50px', lineHeight: '50ox'
        }).click(function () { container.animate({ bottom: '-100%' }, 100) })
        $('#my-container p').css({ fontSize: '16px', padding: '0 20px', margin: 0, lineHeight: '50px' });
        $("#my-container textarea").css({ width: '400px', height: '200px' });
        $("#my-container #btn").css({width: '80px', height: '40px'}).click(run);

        container.animate({ bottom: 0 }, 100);
    }

    function log(text, word) {
        const keywords = getKeywords();
        let s = (keywords.indexOf(word) + 1) + '/' + keywords.length;
        $('#my-container p').text(text + '    ' + s);
    }

    // 从输入框取得关键词
    function getKeywords() {
        return String($("#my-container textarea").val()).trim().split(/\n|,|\t/g).filter(i => !!i);
    }

    function getTargetProductId() {
        const id = String($("#my-container #productId").val()).trim();
        return id ? id : unsafeWindow.location.href.match(/\/(\d{6,})/)[1];
    }

    function outPut(json) {
        let html = `<ul id="myUl">`;
        const lis = Object.keys(json).map(keyword => {
            const sort = json[keyword][0] === 0 ? '前4页未发现' : json[keyword][0];
            const sort_real = json[keyword][1] === 0 ? '前4页未发现' : json[keyword][1];
            resultForCopy[keyword] = sort_real === '前4页未发现' ? '-' : sort_real;
            if (sort.includes && sort.includes('未发现')) { wordsWithoutAd.push(keyword) }
            return `<li><a href="https://www.walmart.com/search?q=${keyword}" target="_blank">${keyword}</a>: 含广告位排名${sort}，去除广告位排名${sort_real}</li>`;
        }).join('');
        html += lis + '</ul>';
        const ul = $(html);
        ul.css({float: 'left', overflow: 'auto', maxHeight: '600px'});
        $("#my-container").append(ul);
        $("#myUl li:not(:contains('未发现'))").css({'color':'green'}).find('a').css({color: 'green', 'textDecoration': 'none'});
        $("li:contains('未发现')").css({'color':'#e4393c'}).find('a').css({'color': '#e4393c', 'textDecoration': 'none'});
        const button = $(`<button id="copyBtn">复制自然排名</button>`);
        let copyText = Object.keys(resultForCopy).map(w => w + '\t' + resultForCopy[w]).join('\n');
        button.css({fontSize: '18px', float: 'left', margin: '10px 0 0 30px', cursor: 'pointer'}).click(function(){
            GM_setClipboard(copyText);
        });
        $("#my-container").append(button);
        const btn = $(`<button id="copyBtnNo">复制无广告词</button>`);
        btn.css({fontSize: '18px', float: 'left', margin: '10px 0 0 30px', cursor: 'pointer'}).click(function() {
            GM_setClipboard(wordsWithoutAd.join('\n'));
        })
        $("#my-container").append(btn);

        const copyAll = $(`<button id="copyBtnAll">复制全部排名</button>`);
        copyAll.css({fontSize: '18px', float: 'left', margin: '10px 0 0 30px', cursor: 'pointer'}).click(function() {
            let text = Object.keys(info).map(keyword => keyword + '\t' + info[keyword][0]).join('\n');
            GM_setClipboard(text);
        })
        $("#my-container").append(copyAll);
    }

    function calcSortInfo(json) {
        const id = getTargetProductId();
        const result = {};
        Object.keys(json).forEach(keyword => {
            result[keyword] = [];
            const products = json[keyword];
            const products_real = products.filter(p => !p.IsSponsored);
            result[keyword][0] = products.map(p => p.productId).indexOf(id) + 1;
            result[keyword][1] = products_real.map(p => p.productId).indexOf(id) + 1;
        });
        return result;
    }

    async function run() {
        const keywords = getKeywords();
        reset();
        const json = await searchWordInBulk(keywords);
        info = calcSortInfo(json);
        outPut(info);
    }

    async function main() {
        insetDIV();
    }

    async function searchWord(keyword) {
        return new Promise(async resolve => {
            let products = (await collectWord(keyword)).filter(i => i.__typename === "Product");
            products = formatProduct(products);
            log(`${keyword}请求成功`, keyword);
            resolve(products);
        })
    }

    async function searchWordInBulk(keywords) {
        let ws = keywords.slice();
        const result = {};
        return new Promise(resolve => {
            async function loop() {
                if (!ws.length) {
                    resolve(result);
                    return;
                }
                const word = ws.shift();
                const products = await searchWord(word);
                result[word] = products;
                loop();
            }
            loop();
        });
    }

    async function collectWord(word) {
        const page1 = await requestWord(word);
        const page2 = await requestWord(word, 2);
        const page3 = await requestWord(word, 3);
        const page4 = await requestWord(word, 4);
        return page1.concat(page2).concat(page3).concat(page4);
    }

    function formatProduct(products) {
        return products.map((i, n) => {
            return {
                No: n + 1,
                productId: i.usItemId,
                IsSponsored: !!i.sponsoredProduct,
            };
        });
    }

    function requestWord(word, page = 1) {
        var url = 'https://www.walmart.com/search?q=' + formatWord(word) + '&page=' + page + '&affinityOverride=default';
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: "GET",
                url,
                onload: async function (res) {
                    let result
                    try {
                        const reg = /<script\b(?:\s+[^>]*)?__NEXT_DATA__(?:[^>]*)?>(.*?)<\/script\s*>/i;
                        const text = res.responseText.match(reg)[1];
                        result = JSON.parse(text).props.pageProps.initialData.searchResult.itemStacks[0].items;
                        log(`${word}第${page}页ok`, word);
                    } catch (err) {
                        if (isRobotVerification(res.responseText)) {
                            alert('robot');
                            await pauseToWaitVerification();
                            result = await requestWord(word, page);
                        }
                    } finally {
                        resolve(result);
                    }
                }
            });
        })
    }

    function formatWord(word) {
        return word.replace(/\s/g, '+');
    }

    function isRobotVerification(html) {
        return html.includes('<title>Robot or human?</title>');
    }

    function pauseToWaitVerification() {
        continueFlag = false;
        insertElement();
        return new Promise(resolve => {
            (function loop() {
                const fn = continueFlag ? resolve : loop;
                setTimeout(fn, 950);
            })();
        });
    }

    function reset() {
        $('#myUl').remove();
        $('#copyBtnNo').remove();
        $('#copyBtn').remove();
        $('#clickMe').remove();
        $('#copyBtnAll').remove();
    }

    function insertElement() {
        const el = $("<div id='clickMe'></div>");
        el.css({width: '80%', height: '80%', position: 'fixed', zIndex: 200, left: '10%', top: '10%', background: 'pink'})
        el.click(function() {
            continueFlag = true;
            el.remove();
        })
        $('body').append(el);
    }
})();